/**
 * Token管理工具类
 * 统一处理token的存储、获取和同步，解决多种token格式共存的问题
 */
import { getDeviceId } from './device.js';

// Token存储键名常量
const TOKEN_KEY = 'unified_app_token'; // 自定义统一键名
const TOKEN_EXPIRED_KEY = 'unified_token_expired'; // 自定义过期时间键名

// uniCloud官方键名
const UNI_ID_TOKEN_KEY = 'uni_id_token'; // uniCloud官方token键名
const UNI_ID_TOKEN_EXPIRED_KEY = 'uni_id_token_expired'; // uniCloud官方过期时间键名

// 历史token存储键
const HISTORY_TOKEN_KEY = 'history_token'; // 历史token列表
const HISTORY_TOKEN_MAX_COUNT = 3; // 最多保存的历史token数量
const HISTORY_TOKEN_EXPIRE = 24 * 60 * 60 * 1000; // 历史token保留24小时

// 全局刷新锁键名
const GLOBAL_REFRESH_LOCK_KEY = 'global_token_refresh_lock';
// 全局刷新锁超时时间（毫秒）
const REFRESH_LOCK_TIMEOUT = 30 * 1000; // 30秒，防止锁定状态卡死
// 全局刷新时间记录
const LAST_REFRESH_TIME_KEY = 'last_token_refresh_time';
// 最小刷新间隔时间（毫秒）
const MIN_REFRESH_INTERVAL = 5 * 60 * 1000; // 5分钟

// 兼容旧键名的常量，仅用于迁移
const OLD_TOKEN_KEYS = ['token'];
const OLD_EXPIRED_KEYS = ['token_expired'];

/**
 * 同步token存储，确保所有token键名的值保持一致
 * 这个方法用于修复某些页面使用旧token键名的问题
 * @returns {String} 当前有效的token
 */
export function syncTokenStorage() {
  console.log('执行token存储同步...');
  
  // 获取当前token
  const token = getToken();
  
  // 确保所有旧token键都存储了当前token
  if (token) {
    for (const key of OLD_TOKEN_KEYS) {
      // 同步旧键名
      uni.setStorageSync(key, token);
    }
    
    // 同时确保统一键和官方键也都有相同的token
    uni.setStorageSync(TOKEN_KEY, token);
    uni.setStorageSync(UNI_ID_TOKEN_KEY, token);
    
    // 获取并同步过期时间
    const expireTime = getTokenExpireTime();
    if (expireTime) {
      for (const key of OLD_EXPIRED_KEYS) {
        uni.setStorageSync(key, expireTime);
      }
      
      uni.setStorageSync(TOKEN_EXPIRED_KEY, expireTime);
      uni.setStorageSync(UNI_ID_TOKEN_EXPIRED_KEY, expireTime);
    }
    
    console.log('Token存储同步完成');
  } else {
    console.log('没有有效token，跳过同步');
  }
  
  return token;
}

/**
 * 获取当前token
 * @param {Boolean} fallbackToHistory 是否在主token无效时尝试使用历史token
 * @returns {String} 当前有效的token
 */
export function getToken(fallbackToHistory = true) {
  // 优先获取官方键名的token
  let token = uni.getStorageSync(UNI_ID_TOKEN_KEY);
  
  // 如果官方键名没有，尝试从自定义键获取
  if (!token) {
    token = uni.getStorageSync(TOKEN_KEY);
  }
  
  // 如果两者都没有，尝试从旧键迁移
  if (!token) {
    token = migrateOldTokens();
  }

  // 如果当前token无效且允许回退到历史token
  if (!token && fallbackToHistory) {
    token = getValidHistoryToken();
    if (token) {
      console.log('主token无效，使用历史token');
    }
  }
  
  return token || '';
}

/**
 * 从历史记录中获取有效的token
 * @returns {String} 有效的历史token
 */
function getValidHistoryToken() {
  try {
    const historyStr = uni.getStorageSync(HISTORY_TOKEN_KEY);
    if (!historyStr) return '';
    
    const history = JSON.parse(historyStr);
    if (!Array.isArray(history) || history.length === 0) return '';
    
    const now = Date.now();
    
    // 按照过期时间倒序排列，优先使用最近的token
    const validTokens = history
      .filter(item => item.token && item.expireTime && item.expireTime > now)
      .sort((a, b) => b.expireTime - a.expireTime);
    
    if (validTokens.length > 0) {
      return validTokens[0].token;
    }
    
    return '';
  } catch (e) {
    console.error('获取历史token失败', e);
    return '';
  }
}

/**
 * 迁移旧的token到新的统一键
 * @returns {String} 迁移后的token
 */
function migrateOldTokens() {
  console.log('尝试迁移旧token到统一存储...');
  
  // 检查所有旧键名
  let token = '';
  let expireTime = 0;
  
  // 遍历旧token键
  for (const key of OLD_TOKEN_KEYS) {
    const oldToken = uni.getStorageSync(key);
    if (oldToken) {
      console.log(`从旧键 ${key} 找到token`);
      token = oldToken;
      break;
    }
  }
  
  // 遍历旧过期时间键
  for (const key of OLD_EXPIRED_KEYS) {
    const oldExpireTime = uni.getStorageSync(key);
    if (oldExpireTime) {
      console.log(`从旧键 ${key} 找到过期时间`);
      expireTime = oldExpireTime;
      break;
    }
  }
  
  // 如果找到了旧的token，存储到新键
  if (token) {
    console.log('迁移token到统一存储');
    setToken(token, expireTime);
    
    // 清除旧的token存储
    clearOldTokens();
  }
  
  return token;
}

/**
 * 清除所有旧的token存储
 */
function clearOldTokens() {
  // 清除所有旧的token键
  for (const key of OLD_TOKEN_KEYS) {
    uni.removeStorageSync(key);
  }
  
  // 清除所有旧的过期时间键
  for (const key of OLD_EXPIRED_KEYS) {
    uni.removeStorageSync(key);
  }
  
  console.log('已清除所有旧的token存储');
}

/**
 * 添加token到历史记录
 * @param {String} token token值
 * @param {Number} expireTime 过期时间戳
 */
function addTokenToHistory(token, expireTime) {
  if (!token || !expireTime) return;
  
  try {
    let history = [];
    const historyStr = uni.getStorageSync(HISTORY_TOKEN_KEY);
    
    if (historyStr) {
      history = JSON.parse(historyStr);
      if (!Array.isArray(history)) history = [];
    }
    
    // 检查是否已存在相同token
    const existIndex = history.findIndex(item => item.token === token);
    if (existIndex !== -1) {
      // 如果已存在，更新过期时间
      history[existIndex].expireTime = expireTime;
      history[existIndex].savedAt = Date.now();
    } else {
      // 添加新的token记录
      history.push({
        token,
        expireTime,
        savedAt: Date.now()
      });
    }
    
    // 清理过期token和超出数量限制的token
    cleanHistoryTokens(history);
    
    // 保存历史记录
    uni.setStorageSync(HISTORY_TOKEN_KEY, JSON.stringify(history));
  } catch (e) {
    console.error('添加token到历史记录失败', e);
  }
}

/**
 * 清理历史token
 * @param {Array} history 历史token列表
 */
function cleanHistoryTokens(history) {
  if (!Array.isArray(history)) return [];
  
  const now = Date.now();
  
  // 过滤出所有有效的token
  let validTokens = history.filter(item => {
    // 检查token是否有效且没超过保留时长
    const isExpired = item.expireTime < now;
    const isTooOld = (now - item.savedAt) > HISTORY_TOKEN_EXPIRE;
    return !isExpired && !isTooOld;
  });
  
  // 如果超过最大数量，保留最新的几个
  if (validTokens.length > HISTORY_TOKEN_MAX_COUNT) {
    validTokens.sort((a, b) => b.savedAt - a.savedAt);
    validTokens = validTokens.slice(0, HISTORY_TOKEN_MAX_COUNT);
  }
  
  return validTokens;
}

/**
 * 设置token，同时存储到统一键名和uniCloud官方键名下
 * 并保存旧token到历史记录
 * @param {String} token token值
 * @param {Number} expireTime 过期时间戳（可选）
 */
export function setToken(token, expireTime) {
  if (!token) return;
  
  // 先获取当前token，准备保存到历史记录
  const currentToken = getToken(false);
  const currentExpireTime = getTokenExpireTime();
  
  // 如果当前有token且与新token不同，将其加入历史记录
  if (currentToken && currentToken !== token && currentExpireTime) {
    addTokenToHistory(currentToken, currentExpireTime);
  }
  
  // 存储token到统一键
  uni.setStorageSync(TOKEN_KEY, token);
  
  // 同时存储到uniCloud官方键名，确保云函数可以读取
  uni.setStorageSync(UNI_ID_TOKEN_KEY, token);
  
  // 如果有过期时间，则转换为时间戳并存储
  if (expireTime) {
    let expireTimestamp;
    
    // 处理不同格式的过期时间
    if (typeof expireTime === 'number') {
      expireTimestamp = expireTime;
    } else if (typeof expireTime === 'string') {
      expireTimestamp = new Date(expireTime).getTime();
    }
    
    if (expireTimestamp) {
      // 同时存储到两个键名下
      uni.setStorageSync(TOKEN_EXPIRED_KEY, expireTimestamp);
      uni.setStorageSync(UNI_ID_TOKEN_EXPIRED_KEY, expireTimestamp);
    }
  }
  
  console.log('Token已更新到统一存储和uniCloud官方存储');
}

/**
 * 清除token及相关存储
 * @param {Boolean} keepHistory 是否保留历史token记录
 */
export function clearToken(keepHistory = true) {
  console.log('清除token及相关存储');
  
  // 如果需要保留历史记录，先把当前token加入历史
  if (keepHistory) {
    const currentToken = getToken(false);
    const currentExpireTime = getTokenExpireTime();
    if (currentToken && currentExpireTime) {
      addTokenToHistory(currentToken, currentExpireTime);
    }
  }
  
  // 清除统一键
  uni.removeStorageSync(TOKEN_KEY);
  uni.removeStorageSync(TOKEN_EXPIRED_KEY);
  
  // 清除uniCloud官方键
  uni.removeStorageSync(UNI_ID_TOKEN_KEY);
  uni.removeStorageSync(UNI_ID_TOKEN_EXPIRED_KEY);
  
  // 同时清除旧键，确保完全清除
  clearOldTokens();
  
  // 如果不保留历史记录，则清除历史
  if (!keepHistory) {
    uni.removeStorageSync(HISTORY_TOKEN_KEY);
  }
  
  // 清除用户信息
  uni.removeStorageSync('userInfo');
  
  // 清除登录信息
  uni.removeStorageSync('loginInfo');
}

/**
 * 获取token过期时间
 * @returns {Number} 过期时间戳
 */
export function getTokenExpireTime() {
  // 首先尝试从官方键获取
  let expireTime = uni.getStorageSync(UNI_ID_TOKEN_EXPIRED_KEY);
  
  // 如果没有，尝试从统一键获取
  if (!expireTime) {
    expireTime = uni.getStorageSync(TOKEN_EXPIRED_KEY);
  }
  
  // 如果都没有，尝试从旧键获取
  if (!expireTime) {
    for (const key of OLD_EXPIRED_KEYS) {
      const oldExpireTime = uni.getStorageSync(key);
      if (oldExpireTime) {
        expireTime = oldExpireTime;
        // 迁移到新键
        uni.setStorageSync(TOKEN_EXPIRED_KEY, oldExpireTime);
        uni.setStorageSync(UNI_ID_TOKEN_EXPIRED_KEY, oldExpireTime);
        break;
      }
    }
  }
  
  return expireTime || 0;
}

/**
 * 检查token是否即将过期（小于2小时）
 * @returns {Boolean} 是否即将过期
 */
export function isTokenExpiringSoon() {
  const expireTime = getTokenExpireTime();
  if (!expireTime) return false;
  
  const currentTime = new Date().getTime();
  const twoHours = 2 * 60 * 60 * 1000; // 2小时的毫秒数
  
  return currentTime > expireTime - twoHours;
}

/**
 * 检查token是否已过期
 * @returns {Boolean} 是否已过期
 */
export function isTokenExpired() {
  const expireTime = getTokenExpireTime();
  if (!expireTime) return false;
  
  const currentTime = new Date().getTime();
  return currentTime > expireTime;
}

/**
 * 更新用户信息中的token
 * @param {String} newToken 新token
 * @param {Number} expireTime 过期时间戳
 */
function updateUserInfoToken(newToken, expireTime) {
  try {
    const userInfoStr = uni.getStorageSync('userInfo');
    if (userInfoStr) {
      const userInfo = JSON.parse(userInfoStr);
      userInfo.token = newToken;
      if (expireTime) {
        userInfo.expire_time = expireTime;
      }
      uni.setStorageSync('userInfo', JSON.stringify(userInfo));
    }
  } catch (e) {
    console.error('更新用户信息中的token失败', e);
  }
}

/**
 * 获取完整的token数据，包括token和设备ID
 * @returns {Object} token数据
 */
export function getTokenData() {
  return {
    token: getToken(),
    device_id: getDeviceId()
  };
}

/**
 * 将对象格式的token统一转换为字符串格式
 * @param {Object|String} tokenObj token对象或字符串
 * @returns {String} 标准化的token字符串
 */
export function normalizeToken(tokenObj) {
  if (!tokenObj) return '';
  
  // 如果是字符串直接返回
  if (typeof tokenObj === 'string') return tokenObj;
  
  // 如果是对象，尝试获取token属性
  if (typeof tokenObj === 'object') {
    if (tokenObj.token) return tokenObj.token;
    if (tokenObj.uni_id_token) return tokenObj.uni_id_token;
  }
  
  // 如果都不符合，返回空字符串
  console.warn('无法标准化token:', tokenObj);
  return '';
}

/**
 * 移除token（已弃用，请使用clearToken）
 */
export function removeToken() {
  clearToken();
}

/**
 * 检查token是否有效
 * @returns {Boolean} token是否有效
 */
export function isTokenValid() {
  const token = getToken();
  
  if (!token) return false;
  
  const expireTime = getTokenExpireTime();
  
  // 如果没有过期时间，假设token有效
  if (!expireTime) return true;
  
  // 检查是否已过期
  return Date.now() < expireTime;
}

/**
 * 清理所有过期的历史token
 */
export function cleanupExpiredTokens() {
  try {
    const historyStr = uni.getStorageSync(HISTORY_TOKEN_KEY);
    if (!historyStr) return;
    
    const history = JSON.parse(historyStr);
    if (!Array.isArray(history)) {
      uni.removeStorageSync(HISTORY_TOKEN_KEY);
      return;
    }
    
    const cleanedHistory = cleanHistoryTokens(history);
    uni.setStorageSync(HISTORY_TOKEN_KEY, JSON.stringify(cleanedHistory));
  } catch (e) {
    console.error('清理过期token失败', e);
  }
}

/**
 * 全局刷新锁机制 - 获取刷新锁状态
 * 用于确保在多个页面间只有一个token刷新请求在进行
 * @returns {Boolean} 是否有其他页面正在刷新token
 */
export function isRefreshingGlobally() {
  try {
    const lockInfo = uni.getStorageSync(GLOBAL_REFRESH_LOCK_KEY);
    if (!lockInfo) return false;
    
    // 解析锁信息
    const lockData = JSON.parse(lockInfo);
    const now = Date.now();
    
    // 检查锁是否已过期（超时机制，防止某个页面崩溃导致锁永久存在）
    if (lockData.timestamp && now - lockData.timestamp > REFRESH_LOCK_TIMEOUT) {
      console.log('检测到过期的刷新锁，自动释放');
      releaseGlobalRefreshLock();
      return false;
    }
    
    return lockData.locked === true;
  } catch (e) {
    console.error('获取全局刷新锁状态失败', e);
    return false;
  }
}

/**
 * 全局刷新锁机制 - 尝试获取刷新锁
 * @returns {Boolean} 是否成功获取锁
 */
export function acquireGlobalRefreshLock() {
  try {
    // 如果已经有锁，则获取失败
    if (isRefreshingGlobally()) {
      return false;
    }
    
    // 设置刷新锁
    const lockData = {
      locked: true,
      timestamp: Date.now(),
      pageId: Math.random().toString(36).substring(2, 10) // 生成一个随机页面ID
    };
    
    uni.setStorageSync(GLOBAL_REFRESH_LOCK_KEY, JSON.stringify(lockData));
    console.log('成功获取全局刷新锁');
    return true;
  } catch (e) {
    console.error('获取全局刷新锁失败', e);
    return false;
  }
}

/**
 * 全局刷新锁机制 - 释放刷新锁
 */
export function releaseGlobalRefreshLock() {
  try {
    uni.removeStorageSync(GLOBAL_REFRESH_LOCK_KEY);
    console.log('全局刷新锁已释放');
  } catch (e) {
    console.error('释放全局刷新锁失败', e);
  }
}

/**
 * 获取最后一次token刷新时间
 * @returns {Number} 最后刷新时间戳
 */
export function getLastRefreshTime() {
  try {
    return uni.getStorageSync(LAST_REFRESH_TIME_KEY) || 0;
  } catch (e) {
    console.error('获取最后刷新时间失败', e);
    return 0;
  }
}

/**
 * 设置最后一次token刷新时间
 */
export function setLastRefreshTime() {
  try {
    uni.setStorageSync(LAST_REFRESH_TIME_KEY, Date.now());
  } catch (e) {
    console.error('设置最后刷新时间失败', e);
  }
}

/**
 * 检查是否满足最小刷新间隔
 * @returns {Boolean} 是否可以刷新token
 */
export function canRefreshToken() {
  const lastRefreshTime = getLastRefreshTime();
  const now = Date.now();
  return (now - lastRefreshTime) > MIN_REFRESH_INTERVAL;
} 